#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QScrollArea>
#include <QFileDialog>
#include <QDir>
#include <QMessageBox>
#include <QSettings>
#include <QScrollBar>
#include <QDockWidget>
#include <QDebug>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    setContextMenuPolicy(Qt::NoContextMenu);

    m_pixelsInfo = new QLabel("");
    ui->statusBar->addPermanentWidget(m_pixelsInfo);

    QSettings settings;
    settings.setIniCodec("GB2312");
    m_recentFiles = settings.value("recentFileList").toStringList();

    createScene();
    createUndoView();
    createActions();
    createToolbar();
    createDialog();

    m_minGray = 255;
    m_maxGray = 0;
    m_percent = 100;

    m_imode = NEAREST;
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::closeEvent(QCloseEvent *e)
{
    close();
    QApplication::quit();
}

void MainWindow::resizeEvent(QResizeEvent *)
{
    if (viewScaleCombo->currentIndex() == 8)
    {
        ui->actionFit_to_Window->trigger();
    }
}

void MainWindow::loadFile(const QString &fileName, OType type)
{
    m_source = QImage(fileName);
    if (m_source.isNull())
    {
        switch (type)
        {
        case OPEN:
            QMessageBox::information(this, tr("Recent Files"),
                             tr("Can't open the file %1. Maybe the image file has been damaged.")
                             .arg(fileName), "OK", 0);
            break;
        case RECENT:
            switch(QMessageBox::information(this, tr("Recent Files"),
                                 tr("Can't open the file %1. The file doesn't exist or has been damaged.\nDo you want to delete it from the recent file list?")
                                 .arg(fileName), "Yes", "No", 0, 1))
            {
            case 0:
                m_recentFiles.removeAll(fileName);
                updateRecentFileActions();
                break;
            case 1:
                break;
            }
            break;
        }
        return;
    }

    setWindowTitle("DIP-" + fileName);
    m_current = QImage(m_source);
    m_imageItem->setPixmap(QPixmap::fromImage(m_source));

    m_undoStack->clear();

    m_percent = 100;
    viewScaleCombo->setCurrentIndex(3);

    ui->actionSource_Image->setEnabled(true);
    ui->actionGray_Image->setEnabled(true);
    ui->actionBrightness_Contrast->setEnabled(true);
    ui->actionManual->setEnabled(true);
    ui->menuAutomatic->setEnabled(true);
    ui->menuTransform->setEnabled(true);
    ui->menuEdge_Detect->setEnabled(true);
    ui->menuFilter->setEnabled(true);
    ui->menuWarp->setEnabled(true);
    ui->actionSharpen->setEnabled(true);
    ui->actionMosaic->setEnabled(true);
    ui->actionLighting->setEnabled(true);
    ui->actionSave->setEnabled(true);
    ui->actionScale->setEnabled(true);
    ui->actionRotate->setEnabled(true);
    ui->thresholdToolBar->setEnabled(true);
    ui->convolutionToolBar->setEnabled(true);
    ui->transformToolBar->setEnabled(true);

    QString str = QString::number(m_current.width()) + " pixels X " +
            QString::number(m_current.height()) + " pixels.";
    m_pixelsInfo->setText(str);

    m_recentFiles.removeAll(fileName);
    m_recentFiles.prepend(fileName);
    while (m_recentFiles.size() > MaxRecentFiles)
    {
        m_recentFiles.removeLast();
    }

    updateRecentFileActions();
}

void MainWindow::updateRecentFileActions()
{
    QSettings settings;
    settings.setIniCodec("GB2312");
    if (m_recentFiles.count())
    {
        settings.setValue("recentFileList", m_recentFiles);
    }
    else
    {
        settings.clear();
    }

    int numRecentFiles = qMin(m_recentFiles.size(), (int)MaxRecentFiles);

    for (int i = 0; i < numRecentFiles; ++i) {
        QString text = tr("&%1 %2").arg(i + 1).arg(strippedName(m_recentFiles[i]));
        m_recentFileActs[i]->setText(text);
        m_recentFileActs[i]->setData(m_recentFiles[i]);
        m_recentFileActs[i]->setVisible(true);
    }
    for (int j = numRecentFiles; j < MaxRecentFiles; ++j)
    {
        m_recentFileActs[j]->setVisible(false);
    }
}

QString MainWindow::strippedName(const QString &fullFileName)
{
    return QFileInfo(fullFileName).fileName();
}

void MainWindow::getPixelInfo()
{
    QImage temp = QImage(m_imageItem->pixmap().toImage());
    for(int i = 0; i < 256; i++)
    {
        m_tempGrayInfo[i] = 0;
        m_redInfo[i] = 0;
        m_greenInfo[i] = 0;
        m_blueInfo[i] = 0;
    }

    int width = temp.width();
    int height = temp.height();

    if(temp.format() != QImage::Format_Indexed8)
    {
        for (int i = 0; i < height; i++)
        {
            QRgb* sourceRgb = (QRgb*)temp.scanLine(i);
            for (int j = 0; j < width; j++, sourceRgb++)
            {
                uchar R = qRed(*sourceRgb);
                uchar G = qGreen(*sourceRgb);
                uchar B = qBlue(*sourceRgb);
                uchar grayValue = (9798 * R + 19235 * G + 3735 * B) / 32768;
                m_tempGrayInfo[grayValue]++;
                m_redInfo[R]++;
                m_greenInfo[G]++;
                m_blueInfo[B]++;
            }
        }
    }
    else
    {
        for (int i = 0; i < height; i++)
        {
            uchar* grayRgb = temp.scanLine(i);
            for (int j = 0; j < width; j++, grayRgb++)
            {
                uchar grayValue = *grayRgb;
                m_tempGrayInfo[grayValue]++;
            }
        }
    }
}

void MainWindow::createScene()
{
    m_scene = new MyGraphicsScene(this);
    m_scene->setBackgroundBrush(Qt::darkGray);
    m_view = new QGraphicsView(m_scene);
    setCentralWidget(m_view);
    m_imageItem = new ImageItem;
    m_scene->addItem(m_imageItem);
    connect(m_scene, SIGNAL(dragFileSignal(QString)), this, SLOT(loadFile(QString)));
    connect(m_imageItem->getProxy(), SIGNAL(sizeChanged(double,double)),
            this, SLOT(scale(double,double)));
    connect(m_imageItem->getProxy(), SIGNAL(focusOut()), this, SLOT(doTransformFocusOut()));
    connect(m_imageItem->getProxy(), SIGNAL(rotateOccured(double)), this, SLOT(rotate(double)));
    connect(m_imageItem->getProxy(), SIGNAL(pointPixel(QString)),
            ui->statusBar, SLOT(showMessage(QString)));
    connect(m_imageItem->getProxy(), SIGNAL(hoverLeave()), ui->statusBar, SLOT(clearMessage()));
    connect(m_imageItem->getProxy(), SIGNAL(selectedImage(QImage,QPoint)),
            this, SLOT(selectedChanged(QImage,QPoint)));
}

void MainWindow::createUndoView()
{
    m_undoStack = new QUndoStack(this);
    m_historyDock = new QDockWidget;
    m_historyDock->setWindowTitle(tr("History"));
    m_historyDock->setFeatures(QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetClosable);
    m_historyDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
    addDockWidget(Qt::RightDockWidgetArea, m_historyDock);
    QUndoView* m_undoView = new QUndoView(m_undoStack);
    m_historyDock->setWidget(m_undoView);
    m_historyDock->hide();

    connect(m_undoStack, SIGNAL(indexChanged(int)), this, SLOT(getCurrentImage(int)));
    connect(m_historyDock, SIGNAL(visibilityChanged(bool)), ui->actionHistory, SLOT(setChecked(bool)));
}

void MainWindow::createActions()
{
    //File
    connect(ui->actionOpen, SIGNAL(triggered()), this, SLOT(openFile()));
    connect(ui->actionSave, SIGNAL(triggered()), this, SLOT(saveFile()));
    for (int i = 0; i < MaxRecentFiles; ++i) {
        m_recentFileActs[i] = new QAction(this);
        m_recentFileActs[i]->setVisible(false);
        connect(m_recentFileActs[i], SIGNAL(triggered()),
                this, SLOT(openRecentFile()));
    }
    updateRecentFileActions();
    for (int i = 0; i < MaxRecentFiles; ++i)
    {
        ui->menuRecent_Files->addAction(m_recentFileActs[i]);
    }
    ui->menuRecent_Files->addSeparator();
    ui->menuRecent_Files->addAction(ui->actionClear);
    connect(ui->actionClear, SIGNAL(triggered()), this, SLOT(clear()));
    connect(ui->actionExit, SIGNAL(triggered()), this, SLOT(exit()));
    //Edit
    connect(ui->actionGray_Image, SIGNAL(triggered()), this, SLOT(changeToGray()));
    connect(ui->actionSource_Image, SIGNAL(triggered()), this, SLOT(changeToSource()));

    connect(ui->actionUndo, SIGNAL(triggered()), m_undoStack, SLOT(undo()));
    connect(ui->actionRedo, SIGNAL(triggered()), m_undoStack, SLOT(redo()));
    connect(m_undoStack, SIGNAL(canUndoChanged(bool)), ui->actionUndo, SLOT(setEnabled(bool)));
    connect(m_undoStack, SIGNAL(canRedoChanged(bool)), ui->actionRedo, SLOT(setEnabled(bool)));

    connect(ui->actionBrightness_Contrast, SIGNAL(triggered()), this, SLOT(doAdjustment()));

    connect(ui->actionScale, SIGNAL(triggered()), this, SLOT(scale()));

    connect(ui->actionRotate, SIGNAL(triggered()), this, SLOT(rotate()));
    connect(ui->actionRotate_180, SIGNAL(triggered()), this, SLOT(rotate()));
    connect(ui->actionRotate_90, SIGNAL(triggered()), this, SLOT(rotate()));
    connect(ui->actionRotate_90_Anti, SIGNAL(triggered()), this, SLOT(rotate()));

    connect(ui->actionFlip_Horizontal, SIGNAL(triggered()), this, SLOT(flip()));
    connect(ui->actionFlip_Vertical, SIGNAL(triggered()), this, SLOT(flip()));

    connect(ui->actionNearest_Neighbor, SIGNAL(triggered()), this, SLOT(selectInterpolation()));
    connect(ui->actionBilinear, SIGNAL(triggered()), this, SLOT(selectInterpolation()));
    connect(ui->actionBicubic, SIGNAL(triggered()), this, SLOT(selectInterpolation()));
    //View
    connect(ui->actionFileToolBar, SIGNAL(toggled(bool)), ui->fileToolBar, SLOT(setShown(bool)));
    connect(ui->actionTransformToolBar, SIGNAL(toggled(bool)), ui->transformToolBar, SLOT(setShown(bool)));
    connect(ui->actionViewToolBar, SIGNAL(toggled(bool)), ui->viewToolBar, SLOT(setShown(bool)));
    connect(ui->actionThresholdToolBar, SIGNAL(toggled(bool)), ui->thresholdToolBar, SLOT(setShown(bool)));
    connect(ui->actionConvolutionToolBar, SIGNAL(toggled(bool)), ui->convolutionToolBar, SLOT(setShown(bool)));

    connect(ui->action25, SIGNAL(triggered()), this, SLOT(adjustViewSize()));
    connect(ui->action50, SIGNAL(triggered()), this, SLOT(adjustViewSize()));
    connect(ui->action75, SIGNAL(triggered()), this, SLOT(adjustViewSize()));
    connect(ui->action100, SIGNAL(triggered()), this, SLOT(adjustViewSize()));
    connect(ui->action125, SIGNAL(triggered()), this, SLOT(adjustViewSize()));
    connect(ui->action150, SIGNAL(triggered()), this, SLOT(adjustViewSize()));
    connect(ui->action200, SIGNAL(triggered()), this, SLOT(adjustViewSize()));

    connect(ui->actionZoom_In, SIGNAL(triggered()), this, SLOT(adjustViewSize()));
    connect(ui->actionZoom_Out, SIGNAL(triggered()), this, SLOT(adjustViewSize()));

    connect(ui->actionFit_to_Window, SIGNAL(triggered()), this, SLOT(fitToWindow()));

    connect(ui->actionHistory, SIGNAL(toggled(bool)), m_historyDock, SLOT(setShown(bool)));
    //Threshold
    connect(ui->actionManual, SIGNAL(triggered()), this, SLOT(doThreshold()));
    connect(ui->actionOTSU, SIGNAL(triggered()), this, SLOT(doThreshold()));
    connect(ui->actionEntropy, SIGNAL(triggered()), this, SLOT(doThreshold()));
    //Convolution
    connect(ui->actionRoberts_Operator, SIGNAL(triggered()), this, SLOT(doConvolution()));
    connect(ui->actionPrewitt_Operator, SIGNAL(triggered()), this, SLOT(doConvolution()));
    connect(ui->actionSobel_Operator, SIGNAL(triggered()), this, SLOT(doConvolution()));

    connect(ui->actionGauss, SIGNAL(triggered()), this, SLOT(doConvolution()));
    connect(ui->actionMean_Filter, SIGNAL(triggered()), this, SLOT(doConvolution()));
    connect(ui->actionMedian_Filter, SIGNAL(triggered()), this, SLOT(doConvolution()));

    connect(ui->actionSpherize, SIGNAL(triggered()), this, SLOT(doConvolution()));
    connect(ui->actionFrom_polar_to_rectangular, SIGNAL(triggered()), this, SLOT(doConvolution()));
    connect(ui->actionFrom_rectangular_to_polar, SIGNAL(triggered()), this, SLOT(doConvolution()));
    connect(ui->actionWhirlix, SIGNAL(triggered()), this, SLOT(doConvolution()));
    connect(ui->actionWave, SIGNAL(triggered()), this, SLOT(doConvolution()));

    connect(ui->actionSharpen, SIGNAL(triggered()), this, SLOT(doConvolution()));

    connect(ui->actionMosaic, SIGNAL(triggered()), this, SLOT(doConvolution()));

    connect(ui->actionLighting, SIGNAL(triggered()), this, SLOT(doConvolution()));
}

void MainWindow::createToolbar()
{
    ui->fileToolBar->addAction(ui->actionOpen);
    ui->fileToolBar->addAction(ui->actionSave);
    ui->fileToolBar->addSeparator();
    ui->fileToolBar->addAction(ui->actionUndo);
    ui->fileToolBar->addAction(ui->actionRedo);
    ui->fileToolBar->addSeparator();
    ui->fileToolBar->addAction(ui->actionSource_Image);
    ui->fileToolBar->addAction(ui->actionGray_Image);

    ui->transformToolBar->addAction(ui->actionScale);
    ui->transformToolBar->addAction(ui->actionRotate);
    ui->transformToolBar->addSeparator();
    ui->transformToolBar->addAction(ui->actionRotate_180);
    ui->transformToolBar->addAction(ui->actionRotate_90);
    ui->transformToolBar->addAction(ui->actionRotate_90_Anti);
    ui->transformToolBar->addSeparator();
    ui->transformToolBar->addAction(ui->actionFlip_Horizontal);
    ui->transformToolBar->addAction(ui->actionFlip_Vertical);
    transformCombo = new QComboBox;
    QStringList interpolations;
    interpolations << tr("Nearest Neighbor") << tr("Bilinear") << tr("Bicubic");
    transformCombo->addItems(interpolations);
    transformCombo->setCurrentIndex(0);
    connect(transformCombo, SIGNAL(currentIndexChanged(int)),
            this, SLOT(interpolationChanged(int)));
    ui->transformToolBar->addWidget(transformCombo);
    ui->transformToolBar->setEnabled(false);

    viewScaleCombo = new QComboBox;
    QStringList scales;
    scales << tr("25%") << tr("50%") << tr("75%") << tr("100%")
           << tr("125%") << tr("150%") << tr("200%")
           << tr("Customize") << tr("Fit to window");
    viewScaleCombo->addItems(scales);
    viewScaleCombo->setCurrentIndex(3);
    connect(viewScaleCombo, SIGNAL(currentIndexChanged(int)),
            this, SLOT(viewScaleChanged(int)));
    ui->viewToolBar->addAction(ui->actionZoom_In);
    ui->viewToolBar->addAction(ui->actionZoom_Out);
    ui->viewToolBar->addAction(ui->action100);
    ui->viewToolBar->addSeparator();
    ui->viewToolBar->addWidget(viewScaleCombo);

    ui->thresholdToolBar->addAction(ui->actionManual);
    ui->thresholdToolBar->addAction(ui->actionOTSU);
    ui->thresholdToolBar->addAction(ui->actionEntropy);
    ui->thresholdToolBar->setEnabled(false);

    ui->convolutionToolBar->addAction(ui->actionRoberts_Operator);
    ui->convolutionToolBar->addAction(ui->actionPrewitt_Operator);
    ui->convolutionToolBar->addAction(ui->actionSobel_Operator);
    ui->convolutionToolBar->addSeparator();
    ui->convolutionToolBar->addAction(ui->actionGauss);
    ui->convolutionToolBar->addAction(ui->actionMean_Filter);
    ui->convolutionToolBar->addAction(ui->actionMedian_Filter);
    ui->convolutionToolBar->setEnabled(false);

    connect(ui->actionMove, SIGNAL(triggered()), this, SLOT(selectTool()));
    connect(ui->actionSelect, SIGNAL(triggered()), this, SLOT(selectTool()));
    ui->toolBar->addAction(ui->actionMove);
    ui->toolBar->addAction(ui->actionSelect);
}

void MainWindow::createDialog()
{
    m_gaussianDialog = new GaussianDialog;
    connect(m_gaussianDialog, SIGNAL(radiusChanged(int)), this, SLOT(setGaussRadius(int)));
    connect(m_gaussianDialog, SIGNAL(sigmaChanged(double)), this, SLOT(setGaussSigma(double)));
    connect(m_gaussianDialog, SIGNAL(applyFilter(QString)), this, SLOT(ensureChange(QString)));
    connect(m_gaussianDialog, SIGNAL(cancelFilter()), this, SLOT(cancelChange()));

    m_spherizeDialog = new SpherizeDialog;
    connect(m_spherizeDialog, SIGNAL(heightChanged(int)), this, SLOT(setSpherizeHeight(int)));
    connect(m_spherizeDialog, SIGNAL(applyOperator(QString)), this, SLOT(ensureChange(QString)));
    connect(m_spherizeDialog, SIGNAL(cancelOperator()), this, SLOT(cancelChange()));

    m_thresholdDialog = new ThresholdDialog;
    connect(m_thresholdDialog, SIGNAL(threshold1Changed(int)), this, SLOT(setThreshold1(int)));
    connect(m_thresholdDialog, SIGNAL(threshold2Changed(int)), this, SLOT(setThreshold2(int)));
    connect(m_thresholdDialog, SIGNAL(applyOperator(QString)), this, SLOT(ensureChange(QString)));
    connect(m_thresholdDialog, SIGNAL(cancelOperator()), this, SLOT(cancelChange()));

    m_brightnessDialog = new BrightnessDialog;
    connect(m_brightnessDialog, SIGNAL(brightnessChanged(int)), this, SLOT(doBrightnessAdjustment(int)));
    connect(m_brightnessDialog, SIGNAL(contrastChanged(int)), this, SLOT(doContrastAdjustment(int)));
    connect(m_brightnessDialog, SIGNAL(applyOperator(QString)), this, SLOT(ensureChange(QString)));
    connect(m_brightnessDialog, SIGNAL(cancelOperator()), this, SLOT(cancelChange()));

    m_whirlixDialog = new WhirlixDialog;
    connect(m_whirlixDialog, SIGNAL(degreeChanged(int)), this, SLOT(setWhirlixDegree(int)));
    connect(m_whirlixDialog, SIGNAL(applyOperator(QString)), this, SLOT(ensureChange(QString)));
    connect(m_whirlixDialog, SIGNAL(cancelOperator()), this, SLOT(cancelChange()));

    m_mosaicDialog = new MosaicDialog;
    connect(m_mosaicDialog, SIGNAL(sizeChanged(int)), this, SLOT(setMosaicSize(int)));
    connect(m_mosaicDialog, SIGNAL(applyOperator(QString)), this, SLOT(ensureChange(QString)));
    connect(m_mosaicDialog, SIGNAL(cancelOperator()), this, SLOT(cancelChange()));

    m_waveDialog = new WaveDialog;
    connect(m_waveDialog, SIGNAL(parametersChanged(uint,uint,double,uint)),
            this, SLOT(setWaveParameters(uint,uint,double,uint)));
    connect(m_waveDialog, SIGNAL(applyOperator(QString)), this, SLOT(ensureChange(QString)));
    connect(m_waveDialog, SIGNAL(cancelOperator()), this, SLOT(cancelChange()));

    m_lightingDialog = new LightingDialog;
    connect(m_lightingDialog, SIGNAL(parametersChanged(QPoint,int,int)),
            this, SLOT(setLightingParameters(QPoint,int,int)));
    connect(m_lightingDialog, SIGNAL(applyOperator(QString)), this, SLOT(ensureChange(QString)));
    connect(m_lightingDialog, SIGNAL(cancelOperator()), this, SLOT(cancelChange()));
}

QRgb MainWindow::interpolation(double x, double y)
{
    int x1 = (int)x;
    int y1 = (int)y;
    int x2 = x1 + 1;
    int y2 = y1 + 1;

    if (x2 >= m_temp.width())
    {
        x2 = x1;
    }
    if (y2 >= m_temp.height())
    {
        y2 = y1;
    }

    switch (m_imode)
    {
    case MainWindow::NEAREST:
    default:
    {
        if (x - x1 <= 0.5 && y - y1 <= 0.5)
        {
            return m_temp.pixel(x1, y1);
        }
        else if (x - x1 <= 0.5 && y - y1 > 0.5)
        {
            return m_temp.pixel(x1, y2);
        }
        else if (x - x1 > 0.5 && y - y1 <= 0.5)
        {
            return m_temp.pixel(x2, y1);
        }
        else
        {
            return m_temp.pixel(x2, y2);
        }
    }
        break;
    case MainWindow::BILINEAR:
    {
        double u = x - x1;
        double v = y - y1;

        QRgb rgb1 = m_temp.pixel(x1, y1);
        QRgb rgb2 = m_temp.pixel(x2, y1);
        QRgb rgb3 = m_temp.pixel(x1, y2);
        QRgb rgb4 = m_temp.pixel(x2, y2);

        double factor1 = (1 - u) * (1 - v);
        double factor2 = u * (1 - v);
        double factor3 = (1 - u) * v;
        double factor4 = u * v;

        int a = factor1 * qAlpha(rgb1) +
                factor2 * qAlpha(rgb2) +
                factor3 * qAlpha(rgb3) +
                factor4 * qAlpha(rgb4);
        int r = factor1 * qRed(rgb1) +
                factor2 * qRed(rgb2) +
                factor3 * qRed(rgb3) +
                factor4 * qRed(rgb4);
        int g = factor1 * qGreen(rgb1) +
                factor2 * qGreen(rgb2) +
                factor3 * qGreen(rgb3) +
                factor4 * qGreen(rgb4);
        int b = factor1 * qBlue(rgb1) +
                factor2 * qBlue(rgb2) +
                factor3 * qBlue(rgb3) +
                factor4 * qBlue(rgb4);
        return qRgba(r, g, b, a);
    }
        break;
    case MainWindow::BICUBIC:
    {
        double u = x - x1;
        double v = y - y1;

        double su[4], sv[4];
        su[0] = s(u + 1);
        su[1] = s(u);
        su[2] = s(u - 1);
        su[3] = s(u - 2);
        sv[0] = s(v + 1);
        sv[1] = s(v);
        sv[2] = s(v - 1);
        sv[3] = s(v - 2);

        QRgb rgb[16];
        int xx[4] = {x1 - 1, x1, x1 + 1, x1 + 2};
        int yy[4] = {y1 - 1, y1, y1 + 1, y1 + 2};

        if (x1 - 1 < 0)
        {
            xx[0] = 0;
        }
        if (x1 + 1 > m_temp.width() - 1)
        {
            xx[2] = m_temp.width() - 1;
        }
        if (x1 + 2 > m_temp.width() - 1)
        {
            xx[3] = m_temp.width() - 1;
        }
        if (y1 - 1 < 0)
        {
            yy[0] = 0;
        }
        if (y1 + 1 > m_temp.height() - 1)
        {
            yy[2] = m_temp.height() - 1;
        }
        if (y1 + 2 > m_temp.height() - 1)
        {
            yy[3] = m_temp.height() - 1;
        }

        int count = 0;
        for (int i = 0; i < 4; i++)
        {
            for (int j = 0; j < 4; j++)
            {
                rgb[count] = m_temp.pixel(xx[i], yy[j]);
                count++;
            }
        }

        double tempAlpha[4] = {0, 0, 0, 0};
        double tempRed[4] = {0, 0, 0, 0};
        double tempGreen[4] = {0, 0, 0, 0};
        double tempBlue[4] = {0, 0, 0, 0};

        int r, g, b, a;

        count = 0;
        for (int i = 0; i < 4; i++)
        {
            for (int j = 0; j < 4; j++)
            {
                QRgb temp = rgb[count];
                tempAlpha[i] += su[j] * qAlpha(temp);
                tempRed[i] += su[j] * qRed(temp);
                tempGreen[i] += su[j] * qGreen(temp);
                tempBlue[i] += su[j] * qBlue(temp);
                count++;
            }
        }
        a = tempAlpha[0] * sv[0] + tempAlpha[1] * sv[1] +
                tempAlpha[2] * sv[2] + tempAlpha[3] * sv[3];
        r = tempRed[0] * sv[0] + tempRed[1] * sv[1] +
                tempRed[2] * sv[2] + tempRed[3] * sv[3];
        g = tempGreen[0] * sv[0] + tempGreen[1] * sv[1] +
                tempGreen[2] * sv[2] + tempGreen[3] * sv[3];
        b = tempBlue[0] * sv[0] + tempBlue[1] * sv[1] +
                tempBlue[2] * sv[2] + tempBlue[3] * sv[3];

        return qRgba(r, g, b, a);
    }
        break;
    }
}

double MainWindow::s(double x)
{
    double absx = fabs(x);
    if (absx < 1 && absx >= 0)
    {
        return 1 - 5 * absx * absx / 2 + 3 * absx * absx * absx / 2;
    }
    else if (absx >= 1 && absx < 2)
    {
        return 2 - 4 * absx + 5 * absx * absx / 2 - absx * absx * absx / 2;
    }
    else
    {
        return 0;
    }
}

void MainWindow::updateImage(QImage &img)
{
    int x = m_selectedOrigin.x();
    int y = m_selectedOrigin.y();
    int w = m_tempSelected.width();
    int h = m_tempSelected.height();
    if (img.format() == QImage::Format_Indexed8)
    {
        m_tempSelected = m_tempSelected.convertToFormat(QImage::Format_Indexed8);
        for (int i = 0; i < h; i++, y++)
        {
            uchar* srcPtr = img.scanLine(y) + x;
            uchar* dstPtr = m_tempSelected.scanLine(i);
            for (int j = 0; j < w; j++, srcPtr++, dstPtr++)
            {
                *srcPtr = *dstPtr;
            }
        }
    }
    else
    {
        m_tempSelected = m_tempSelected.convertToFormat(img.format());
        for (int i = 0; i < h; i++, y++)
        {
            QRgb* srcPtr = (QRgb*)img.scanLine(y) + x;
            QRgb* dstPtr = (QRgb*)m_tempSelected.scanLine(i);
            for (int j = 0; j < w; j++, srcPtr++, dstPtr++)
            {
                *srcPtr = *dstPtr;
            }
        }
    }
}

void MainWindow::getCurrentImage(int)
{
    m_current = QImage(m_imageItem->pixmap().toImage());
}

void MainWindow::selectedChanged(QImage selected, QPoint origin)
{
    m_tempSelected = QImage(selected);
    m_selectedOrigin = QPoint(origin.x(), origin.y());
}

void MainWindow::selectTool()
{
    QAction* clickedAction = qobject_cast<QAction*>(sender());
    if (clickedAction != NULL)
    {
        if (clickedAction->objectName() == "actionMove")
        {
            m_imageItem->setMode(ImageItem::MOVE);
            ui->actionSelect->setChecked(false);
            ui->actionMove->setChecked(true);
        }
        else if (clickedAction->objectName() == "actionSelect")
        {
            m_imageItem->setMode(ImageItem::SELECT);
            ui->actionSelect->setChecked(true);
            ui->actionMove->setChecked(false);
        }
    }
}

void MainWindow::loadFile(const QString &fileName)
{
    loadFile(fileName, OPEN);
}

void MainWindow::openFile()
{
    QString filename = QFileDialog::getOpenFileName(
       this,
       "Open Pictures",
       QDir::homePath(),
       "Images Files (*.jpg *.jpe *.png *.bmp *.tiff)");
    if(!filename.isNull())
    {
        loadFile(filename, OPEN);
    }
}

void MainWindow::saveFile()
{
    QString filename = QFileDialog::getSaveFileName(
                this,
                "Save Pictures as",
                QDir::homePath(),
                "PNG Pictures (*.png);;JPG Pictures (*.jpg)");
    if (!filename.isNull())
    {
        m_current.convertToFormat(QImage::Format_ARGB32).save(filename);
    }
}

void MainWindow::openRecentFile()
{
    QAction *action = qobject_cast<QAction *>(sender());
    if (action)
    {
        loadFile(action->data().toString(), RECENT);
    }
}

void MainWindow::clear()
{
    m_recentFiles.clear();
    updateRecentFileActions();
}

void MainWindow::exit()
{
    this->close();
}

void MainWindow::changeToGray(bool flag)
{
    for(int i = 0; i < 256; i++)
    {
        m_grayInfo[i] = 0;
    }

    if (m_current.format() == QImage::Format_Indexed8)
    {
        m_gray = QImage(m_current);

        int width = m_gray.width();
        int height = m_gray.height();

        for (int i = 0; i < height; i++)
        {
            uchar* grayRgb = m_gray.scanLine(i);
            for (int j = 0; j < width; j++, grayRgb++)
            {
                int grayValue = *grayRgb;

                m_maxGray = m_maxGray > grayValue ? m_maxGray : grayValue;
                m_minGray = m_minGray < grayValue ? m_minGray : grayValue;
                m_grayInfo[grayValue]++;
            }
        }
    }
    else
    {
        m_gray = QImage(m_current.size(),
                        QImage::Format_Indexed8);

        int width = m_current.width();
        int height = m_current.height();

        for (int i = 0; i < height; i++)
        {
            QRgb* sourceRgb = (QRgb*)m_current.scanLine(i);
            uchar* grayRgb = m_gray.scanLine(i);
            for (int j = 0; j < width; j++, grayRgb++, sourceRgb++)
            {
                uchar R = qRed(*sourceRgb);
                uchar G = qGreen(*sourceRgb);
                uchar B = qBlue(*sourceRgb);
                uchar grayValue = (9798 * R + 19235 * G + 3735 * B) / 32768;
                m_maxGray = m_maxGray > grayValue ? m_maxGray : grayValue;
                m_minGray = m_minGray < grayValue ? m_minGray : grayValue;
                m_grayInfo[grayValue]++;

                *grayRgb = grayValue;
            }
        }
    }
    m_current = QImage(m_gray);
    if (flag)
    {
        m_undoStack->push(new ImageCommand(m_imageItem, m_current, tr("Change the image to grayscale image.")));
    }
}

void MainWindow::changeToSource()
{
    m_current = QImage(m_source);
    m_undoStack->push(new ImageCommand(m_imageItem, m_current, tr("Revert the image to source.")));

    QString str = QString::number(m_current.width()) + " pixels X " +
            QString::number(m_current.height()) + " pixels.";
    m_pixelsInfo->setText(str);
}

void MainWindow::doAdjustment()
{
    QAction* clickedAction = qobject_cast<QAction*>(sender());
    if (clickedAction != NULL)
    {
        if (clickedAction->objectName() == "actionBrightness_Contrast")
        {
            m_brightnessDialog->show();
        }
    }
}

void MainWindow::doBrightnessAdjustment(int brightness)
{
    m_adjustment.setBrightness(brightness);
    m_temp = QImage(m_adjustment.applyAdjustment(m_current));
    m_imageItem->setPixmap(QPixmap::fromImage(m_temp));
}

void MainWindow::doContrastAdjustment(int contrast)
{
    m_adjustment.setContrast(contrast);
    m_temp = QImage(m_adjustment.applyAdjustment(m_current));
    m_imageItem->setPixmap(QPixmap::fromImage(m_temp));
}

void MainWindow::viewScaleChanged(int index)
{
    switch (index)
    {
    case 0:
        ui->action25->trigger();
        break;
    case 1:
        ui->action50->trigger();
        break;
    case 2:
        ui->action75->trigger();
        break;
    case 3:
    default:
        ui->action100->trigger();
        break;
    case 4:
        ui->action125->trigger();
        break;
    case 5:
        ui->action150->trigger();
        break;
    case 6:
        ui->action200->trigger();
        break;
    case 7:
        break;
    case 8:
        ui->actionFit_to_Window->trigger();
        break;
    }
}

void MainWindow::fitToWindow()
{
    int extraHeight = ui->statusBar->height() + ui->menuBar->height()
            + ui->fileToolBar->height();

    double widthFactor = (double)this->width() / m_current.width();
    double heightFactor = (double)(this->height() - extraHeight) / m_current.height();

    double factor = widthFactor < heightFactor ? widthFactor : heightFactor;
    m_percent = factor * 100;
    m_imageItem->resetTransform();
    m_imageItem->scale((double)m_percent / 100, (double)m_percent / 100);

    viewScaleCombo->setCurrentIndex(8);
}

void MainWindow::adjustViewSize()
{
    QAction* clickedAction = qobject_cast<QAction*>(sender());
    if (clickedAction != NULL)
    {
        if (clickedAction->objectName() == "action25")
        {
            m_percent = 25;
            viewScaleCombo->setCurrentIndex(0);
        }
        else if (clickedAction->objectName() == "action50")
        {
            m_percent = 50;
            viewScaleCombo->setCurrentIndex(1);
        }
        else if (clickedAction->objectName() == "action75")
        {
            m_percent = 75;
            viewScaleCombo->setCurrentIndex(2);
        }
        else if (clickedAction->objectName() == "action100")
        {
            m_percent = 100;
            viewScaleCombo->setCurrentIndex(3);
        }
        else if (clickedAction->objectName() == "action125")
        {
            m_percent = 125;
            viewScaleCombo->setCurrentIndex(4);
        }
        else if (clickedAction->objectName() == "action150")
        {
            m_percent = 150;
            viewScaleCombo->setCurrentIndex(5);
        }
        else if (clickedAction->objectName() == "action200")
        {
            m_percent = 200;
            viewScaleCombo->setCurrentIndex(6);
        }
        else if (clickedAction->objectName() == "actionZoom_In")
        {
            m_percent += 10;
            viewScaleCombo->setCurrentIndex(7);
        }
        else if (clickedAction->objectName() == "actionZoom_Out")
        {
            m_percent -= 10;
            viewScaleCombo->setCurrentIndex(7);
        }
    }

    ui->actionZoom_In->setEnabled(m_percent <= 490);
    ui->actionZoom_Out->setEnabled(m_percent > 10);

    m_imageItem->resetTransform();
    m_imageItem->scale((double)m_percent / 100, (double)m_percent / 100);
}

void MainWindow::setThreshold1(int threshold)
{
    m_threshold.setThreshold1(threshold);
    m_temp = QImage(m_threshold.getImage());
    m_imageItem->setPixmap(QPixmap::fromImage(m_threshold.getImage()));
}

void MainWindow::setThreshold2(int threshold)
{
    m_threshold.setThreshold2(threshold);
    m_temp = QImage(m_threshold.getImage());
    m_imageItem->setPixmap(QPixmap::fromImage(m_threshold.getImage()));
}

void MainWindow::doThreshold()
{
    QAction* clickedAction = qobject_cast<QAction*>(sender());
    if (clickedAction != NULL)
    {
        changeToGray(false);

        QString str = tr("");

        if (clickedAction->objectName() == "actionManual")
        {
            m_threshold = Threshold(m_gray, m_grayInfo, m_minGray, m_maxGray, Threshold::OTSU);

            m_thresholdDialog->setThreshold(m_threshold.getThreshold());
            m_thresholdDialog->setGrayInfo(m_grayInfo);
            m_thresholdDialog->show();
        }
        else if (clickedAction->objectName() == "actionOTSU")
        {
            m_threshold = Threshold(m_gray, m_grayInfo, m_minGray, m_maxGray, Threshold::OTSU);
            str = tr("Do the threshold with OTSU.");
            m_current = QImage(m_threshold.getImage());
            m_undoStack->push(new ImageCommand(m_imageItem, m_current, str));
        }
        else if (clickedAction->objectName() == "actionEntropy")
        {
            m_threshold = Threshold(m_gray, m_grayInfo, m_minGray, m_maxGray, Threshold::ENTROPY);
            str = tr("Do the threshold with Entropy.");
            m_current = QImage(m_threshold.getImage());
            m_undoStack->push(new ImageCommand(m_imageItem, m_current, str));
        }
    }
}

void MainWindow::flip()
{
    QAction* clickedAction = qobject_cast<QAction*>(sender());

    if (clickedAction != NULL)
    {
        m_temp = m_current.convertToFormat(QImage::Format_ARGB32);

        QImage flipped = QImage(m_temp.size(),
                                m_temp.format());

        int width = m_temp.width();
        int height = m_temp.height();

        QRgb* sourceRgb = (QRgb*)m_temp.bits();
        QRgb* flippedRgb = (QRgb*)flipped.bits();

        QString str = tr("");
        if (clickedAction->objectName() == "actionFlip_Horizontal")
        {
            for (int i = 0; i < height; i++)
            {
                int wOffset = (i + 1) * width;
                for (int j = 1; j <= width; j++)
                {
                    *flippedRgb = *(sourceRgb + wOffset - j);
                    flippedRgb++;
                }
            }
            str = tr("Horizotally flip.");
        }
        else if(clickedAction->objectName() == "actionFlip_Vertical")
        {
            for (int i = 0; i < height; i++)
            {
                int wOffset = (height - 1 - i) * width;
                for (int j = 0; j < width; j++)
                {
                    *flippedRgb = *(sourceRgb + wOffset + j);
                    flippedRgb++;
                }
            }
            str = tr("Vertically flip.");
        }
        flipped = flipped.convertToFormat(m_current.format());
        m_current = QImage(flipped);
        m_undoStack->push(new ImageCommand(m_imageItem, m_current, str));
    }
}

void MainWindow::selectInterpolation()
{
    QAction* clickedAction = qobject_cast<QAction*>(sender());
    if (clickedAction != NULL)
    {
        if (clickedAction->objectName() == "actionNearest_Neighbor")
        {
            ui->actionNearest_Neighbor->setChecked(true);
            ui->actionBilinear->setChecked(false);
            ui->actionBicubic->setChecked(false);
            m_imode = MainWindow::NEAREST;
            transformCombo->setCurrentIndex(0);
        }
        else if (clickedAction->objectName() == "actionBilinear")
        {
            ui->actionNearest_Neighbor->setChecked(false);
            ui->actionBilinear->setChecked(true);
            ui->actionBicubic->setChecked(false);
            m_imode = MainWindow::BILINEAR;
            transformCombo->setCurrentIndex(1);
        }
        else if (clickedAction->objectName() == "actionBicubic")
        {
            ui->actionNearest_Neighbor->setChecked(false);
            ui->actionBilinear->setChecked(false);
            ui->actionBicubic->setChecked(true);
            m_imode = MainWindow::BICUBIC;
            transformCombo->setCurrentIndex(2);
        }
    }
}

void MainWindow::interpolationChanged(int index)
{
    switch (index)
    {
    case 0:
    default:
        ui->actionNearest_Neighbor->trigger();
        break;
    case 1:
        ui->actionBilinear->trigger();
        break;
    case 2:
        ui->actionBicubic->trigger();
        break;
    }
}

void MainWindow::scale()
{
    m_scene->setFocusItem(m_imageItem);
    m_imageItem->setTransformType(ImageItem::RESIZE);
    m_imageItem->showFocusItems(true);
    m_imageItem->setMode(ImageItem::TRANSFORM);

    ui->menuBar->setEnabled(false);
    ui->fileToolBar->setEnabled(false);
    ui->transformToolBar->setEnabled(false);
    ui->viewToolBar->setEnabled(false);
    ui->thresholdToolBar->setEnabled(false);
    ui->convolutionToolBar->setEnabled(false);
}

void MainWindow::scale(double widthAfter, double heightAfter)
{
    m_temp = m_current.convertToFormat(QImage::Format_ARGB32);

    int width = m_temp.width();
    int height = m_temp.height();

    double widthFactor = widthAfter / width;
    double heightFactor = heightAfter / height;

    QImage afterImage = QImage(widthAfter, heightAfter, m_temp.format());

    for (int i = 0; i < heightAfter; i++)
    {
        QRgb* afterPtr = (QRgb*)afterImage.scanLine(i);
        for (int j = 0; j < widthAfter; j++, afterPtr++)
        {
            double beforeX = j / widthFactor;
            double beforeY = i / heightFactor;

            *afterPtr = interpolation(beforeX, beforeY);
        }
    }

    afterImage = afterImage.convertToFormat(m_current.format());
    m_temp = QImage(afterImage);
    m_imageItem->setPixmap(QPixmap::fromImage(afterImage));

    QString str = QString::number(m_temp.width()) + " pixels X " +
            QString::number(m_temp.height()) + " pixels.";
    m_pixelsInfo->setText(str);
}

void MainWindow::doTransformFocusOut()
{
    switch (QMessageBox::information(this, "Transformation occurs.",
                             "The picture is changed.\nDo you want to apply the transformation?",
                             "Apply", "Cancel", 0, 1))
    {
    case 0:
        if (ui->actionMove->isChecked())
        {
            m_imageItem->setMode(ImageItem::MOVE);
        }
        else
        {
            m_imageItem->setMode(ImageItem::SELECT);
        }
        m_imageItem->setPixmap(QPixmap::fromImage(m_current));
        m_current = QImage(m_temp);
        m_undoStack->push(new ImageCommand(m_imageItem, m_current, tr("Do the transformation.")));
        break;
    case 1:
        if (ui->actionMove->isChecked())
        {
            m_imageItem->setMode(ImageItem::MOVE);
        }
        else
        {
            m_imageItem->setMode(ImageItem::SELECT);
        }
        m_imageItem->setPixmap(QPixmap::fromImage(m_current));

        QString str = QString::number(m_current.width()) + " pixels X " +
                QString::number(m_current.height()) + " pixels.";
        m_pixelsInfo->setText(str);
        break;
    }
    m_imageItem->showFocusItems(false);

    ui->menuBar->setEnabled(true);
    ui->fileToolBar->setEnabled(true);
    ui->transformToolBar->setEnabled(true);
    ui->viewToolBar->setEnabled(true);
    ui->convolutionToolBar->setEnabled(true);
    ui->thresholdToolBar->setEnabled(true);
}

void MainWindow::rotate()
{
    QAction* clickedAction = qobject_cast<QAction*>(sender());
    double degree = 0;
    if (clickedAction != NULL)
    {
        if (clickedAction->objectName() == "actionRotate")
        {
            m_scene->setFocusItem(m_imageItem);
            m_imageItem->setTransformType(ImageItem::ROTATE);
            m_imageItem->showFocusItems(true);
            m_imageItem->setMode(ImageItem::TRANSFORM);

            ui->menuBar->setEnabled(false);
            ui->fileToolBar->setEnabled(false);
            ui->transformToolBar->setEnabled(false);
            ui->viewToolBar->setEnabled(false);
            ui->thresholdToolBar->setEnabled(false);
            ui->convolutionToolBar->setEnabled(false);
        }
        else if (clickedAction->objectName() == "actionRotate_180")
        {
            degree = PI;
            rotate(degree);
            m_imageItem->setPixmap(QPixmap::fromImage(m_current));
            m_current = QImage(m_temp);
            m_undoStack->push(new ImageCommand(m_imageItem, m_current, tr("Rotate 180 degree.")));
        }
        else if (clickedAction->objectName() == "actionRotate_90")
        {
            degree = -PI / 2;
            rotate(degree);
            m_imageItem->setPixmap(QPixmap::fromImage(m_current));
            m_current = QImage(m_temp);
            m_undoStack->push(new ImageCommand(m_imageItem, m_current, tr("Clockwisely rotate 90 degree.")));
        }
        else if (clickedAction->objectName() == "actionRotate_90_Anti")
        {
            degree = PI / 2;
            rotate(degree);
            m_imageItem->setPixmap(QPixmap::fromImage(m_current));
            m_current = QImage(m_temp);
            m_undoStack->push(new ImageCommand(m_imageItem, m_current, tr("Anticlockwisely rotate 90 degree.")));
        }
    }
}

void MainWindow::rotate(double alpha)
{
    m_temp = m_current.convertToFormat(QImage::Format_ARGB32);

    int width = m_temp.width();
    int height = m_temp.height();

    double temp1 = width * cos(alpha);
    double temp2 = height * sin(alpha);
    int widthAfter = abs((int)temp1) + abs((int)temp2);
    temp1 = width * sin(alpha);
    temp2 = height * cos(alpha);
    int heightAfter = abs((int)temp1) + abs((int)temp2);

    int originX = widthAfter / 2;
    int originY = heightAfter / 2;

    QImage afterImage = QImage(widthAfter, heightAfter, m_temp.format());

    for (int i = 0; i < heightAfter; i++)
    {
        QRgb* afterPtr = (QRgb*)afterImage.scanLine(i);
        for (int j = 0; j < widthAfter; j++, afterPtr++)
        {
            int x = j - originX;
            int y = originY - i;
            double beforeX = x * cos(alpha) + y * sin(alpha);
            double beforeY = y * cos(alpha) - x * sin(alpha);
            if (beforeX + width / 2 < 0 || beforeX >= width / 2 ||
                beforeY > height / 2 || beforeY + height / 2 <= 0)
            {
                *afterPtr = qRgba(255, 255, 255, 1);
            }
            else
            {
                *afterPtr = interpolation(beforeX + width / 2, height / 2 - beforeY);
            }
        }
    }

    m_temp = QImage(afterImage);
    m_imageItem->setPixmap(QPixmap::fromImage(afterImage));

    QString str = QString::number(m_temp.width()) + " pixels X " +
            QString::number(m_temp.height()) + " pixels.";
    m_pixelsInfo->setText(str);
}

void MainWindow::doConvolution()
{
    QAction* clickedAction = qobject_cast<QAction*>(sender());
    if (clickedAction != NULL)
    {
        m_selected = QImage(m_tempSelected);
        QImage tempImage = QImage(m_tempSelected.size(),
                                       QImage::Format_Indexed8);
        if (!m_tempSelected.allGray())
        {
            int width = m_tempSelected.width();
            int height = m_tempSelected.height();

            for (int i = 0; i < height; i++)
            {
                QRgb* sourceRgb = (QRgb*)m_tempSelected.scanLine(i);
                uchar* grayRgb = tempImage.scanLine(i);
                for (int j = 0; j < width; j++, sourceRgb++, grayRgb++)
                {
                    if (qAlpha(*sourceRgb) == 0)
                    {
                        *grayRgb = qRgba(0, 0, 0, 0);
                        continue;
                    }
                    int R = qRed(*sourceRgb);
                    int G = qGreen(*sourceRgb);
                    int B = qBlue(*sourceRgb);
                    int grayValue = (9798 * R + 19235 * G + 3735 * B) / 32768;

                    *grayRgb = grayValue;
                }
            }
        }
        else
        {
            tempImage = QImage(m_tempSelected);
        }
        tempImage = QImage(tempImage.convertToFormat(QImage::Format_Indexed8));
        if (clickedAction->objectName() == "actionRoberts_Operator")
        {
            m_tempSelected = QImage(applyRobertsOperator(tempImage, ALL));
            updateImage(m_current);
            m_undoStack->push(new ImageCommand(m_imageItem, m_current, "Detect the edge using Roberts operator."));
        }
        else if (clickedAction->objectName() == "actionPrewitt_Operator")
        {
            m_tempSelected = QImage(applyPrewittOperator(tempImage, ALL));
            updateImage(m_current);
            m_undoStack->push(new ImageCommand(m_imageItem, m_current, "Detect the edge using Prewitt operator."));
        }
        else if (clickedAction->objectName() == "actionSobel_Operator")
        {
            m_tempSelected = QImage(applySobelOperator(tempImage, ALL));
            updateImage(m_current);
            m_undoStack->push(new ImageCommand(m_imageItem, m_current, "Detect the edge using Sobel operator."));
        }
        else if (clickedAction->objectName() == "actionGauss")
        {
            m_gaussianDialog->show();
            m_tempSelected = QImage(m_gaussianFilter.applyGaussOperator(m_tempSelected));
            m_temp = QImage(m_current);
            updateImage(m_temp);
            m_imageItem->setPixmap(QPixmap::fromImage(m_temp));
        }
        else if (clickedAction->objectName() == "actionMean_Filter")
        {
            m_tempSelected = QImage(applyMeanFilter(m_selected));
            updateImage(m_current);
            m_undoStack->push(new ImageCommand(m_imageItem, m_current, "Mean filter."));
        }
        else if (clickedAction->objectName() == "actionMedian_Filter")
        {
            m_tempSelected = QImage(applyMedianFilter(m_selected));
            updateImage(m_current);
            m_undoStack->push(new ImageCommand(m_imageItem, m_current, "Median filter."));
        }
        else if (clickedAction->objectName() == "actionSpherize")
        {
            int width = m_selected.width();
            m_spherizeDialog->setHeightMaximum(width * 3 / 8);
            m_spherizeDialog->setHeight(width / 2);
            m_tempSelected = QImage(applySpherize(width / 2, width * 3 / 8, m_tempSelected));
            m_temp = QImage(m_current);
            updateImage(m_temp);
            m_imageItem->setPixmap(QPixmap::fromImage(m_temp));
            m_spherizeDialog->show();
        }
        else if (clickedAction->objectName() == "actionFrom_polar_to_rectangular")
        {
            m_tempSelected = QImage(applyPolarToRectangular(m_selected));
            updateImage(m_current);
            m_undoStack->push(new ImageCommand(m_imageItem, m_current,
                                               "From polar to rectangular."));
        }
        else if (clickedAction->objectName() == "actionFrom_rectangular_to_polar")
        {
            m_tempSelected = QImage(applyRectangularToPolar(m_selected));
            updateImage(m_current);
            m_undoStack->push(new ImageCommand(m_imageItem, m_current,
                                               "From rectangular to polar."));
        }
        else if (clickedAction->objectName() == "actionWhirlix")
        {
            m_tempSelected = QImage(applyWhirlix(0, m_selected));
            m_temp = QImage(m_current);
            updateImage(m_temp);
            m_imageItem->setPixmap(QPixmap::fromImage(m_temp));
            m_whirlixDialog->show();
        }
        else if (clickedAction->objectName() == "actionWave")
        {
            m_tempSelected = QImage(applyWave(5, 5, 0, HORIZONTAL_WAVE, m_selected));
            m_temp = QImage(m_current);
            updateImage(m_temp);
            m_imageItem->setPixmap(QPixmap::fromImage(m_temp));
            m_waveDialog->show();
//            updateImage(m_current);
//            m_undoStack->push(new ImageCommand(m_imageItem, m_current, "Wave."));
        }
        else if (clickedAction->objectName() == "actionSharpen")
        {
            m_tempSelected = QImage(applySharpen(m_selected));
            updateImage(m_current);
            m_undoStack->push(new ImageCommand(m_imageItem, m_current, "Sharpen."));
        }
        else if (clickedAction->objectName() == "actionMosaic")
        {
            int width = m_selected.width();
            m_mosaicDialog->setSizeMaximum(width / 2);
            m_tempSelected = QImage(applyMosaic(2, m_selected));
            m_temp = QImage(m_current);
            updateImage(m_temp);
            m_imageItem->setPixmap(QPixmap::fromImage(m_temp));
            m_mosaicDialog->show();
        }
        else if (clickedAction->objectName() == "actionLighting")
        {
            m_lightingDialog->setPixmap(m_selected);
            m_lightingDialog->setPosSize(m_selected.width(), m_selected.height());
            m_tempSelected = QImage(applyLighting(QPoint(0, 0), 0, 10, m_selected));
            m_temp = QImage(m_current);
            updateImage(m_temp);
            m_imageItem->setPixmap(QPixmap::fromImage(m_temp));
            m_lightingDialog->show();
        }
    }
}

void MainWindow::setGaussRadius(int radius)
{
    m_gaussianFilter.setRadius(radius);
    m_tempSelected = QImage(m_gaussianFilter.applyGaussOperator(m_selected));
    m_temp = QImage(m_current);
    updateImage(m_temp);
    m_imageItem->setPixmap(QPixmap::fromImage(m_temp));
}

void MainWindow::setGaussSigma(double sigma)
{
    m_gaussianFilter.setSigma(sigma);
    m_tempSelected = QImage(m_gaussianFilter.applyGaussOperator(m_selected));
    m_temp = QImage(m_current);
    updateImage(m_temp);
    m_imageItem->setPixmap(QPixmap::fromImage(m_temp));
}

void MainWindow::setSpherizeHeight(int height)
{
    int width = m_current.width();
    m_tempSelected = QImage(applySpherize(width / 2, height, m_selected));
    m_temp = QImage(m_current);
    updateImage(m_temp);
    m_imageItem->setPixmap(QPixmap::fromImage(m_temp));
}

void MainWindow::setWhirlixDegree(int degree)
{
    m_tempSelected = QImage(applyWhirlix(degree, m_selected));
    m_temp = QImage(m_current);
    updateImage(m_temp);
    m_imageItem->setPixmap(QPixmap::fromImage(m_temp));
}

void MainWindow::setMosaicSize(int size)
{
    m_tempSelected = QImage(applyMosaic(size, m_selected));
    m_temp = QImage(m_current);
    updateImage(m_temp);
    m_imageItem->setPixmap(QPixmap::fromImage(m_temp));
}

void MainWindow::setWaveParameters(uint waveLength, uint amplitude, double phase, uint type)
{
    m_tempSelected = QImage(applyWave(waveLength, amplitude, phase, type, m_selected));
    m_temp = QImage(m_current);
    updateImage(m_temp);
    m_imageItem->setPixmap(QPixmap::fromImage(m_temp));
}

void MainWindow::setLightingParameters(QPoint point, int intensity, int radius)
{
    m_tempSelected = QImage(applyLighting(point, intensity, radius, m_selected));
    m_temp = QImage(m_current);
    updateImage(m_temp);
    m_imageItem->setPixmap(QPixmap::fromImage(m_temp));
}

void MainWindow::ensureChange(QString whatOperation)
{
    m_imageItem->setPixmap(QPixmap::fromImage(m_current));
    m_current = QImage(m_temp);
    m_undoStack->push(new ImageCommand(m_imageItem, m_current, whatOperation));
}

void MainWindow::cancelChange()
{
    m_imageItem->setPixmap(QPixmap::fromImage(m_current));
}

void MainWindow::keyPressEvent(QKeyEvent *e){
    switch(e->key()){
    case Qt::Key_1:
        if (m_recentFiles.isEmpty()) e->ignore();
        loadFile(m_recentFiles.first(), OPEN);
        break;
    default:break;
    }
}
